package com.wg.game.app;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.core.controller.ControllerMgr;
import com.wg.core.event.EventMgr;
import com.wg.core.properties.PropertiesMgr;
import com.wg.core.thread.CoreThreadPool;
import com.wg.db.DataService;
import com.wg.db.annotation.RepositoryScan;
import com.wg.db.repository.RepositoryMgr;
import com.wg.core.script.ScriptManager;
import com.wg.game.GameConfig;
import com.wg.game.ShutdownHook;
import com.wg.net.NetService;
import com.wg.net.server.http.HandleHttpClientRequestMgr;
import com.wg.net.server.http.HandlerInterceptorMgr;
import com.wg.net.handle.HandleServerToServerRequestMgr;
import com.wg.net.handle.HandleTcpClientRequestMgr;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.*;

/**
 * 游戏应用基础类，负责核心组件的生命周期管理
 *
 * @author 少爷123
 */
public abstract class BaseGameApplication extends BaseApplication {
    private static final Log log = LogFactory.get();
    private final RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();

    public BaseGameApplication() {
        // 注册JVM关闭钩子，确保优雅停机
        Runtime.getRuntime().addShutdownHook(new ShutdownHook(this));
    }

    /**
     * 启动应用服务
     *
     * @param args 启动参数
     */
    public void start(String[] args) {
        log.info("正在启动 {} 服务...", getAppName());
        String packageName = getClass().getPackage().getName();
        TimeInterval timer = DateUtil.timer();

        try {
            INST = this;
            // 按顺序初始化核心组件
            initComponents(packageName, args);

            // 标记应用为运行状态
            this.isRunAtomic.set(true);
            log.info("{} 启动成功，总耗时: {}", getAppName(), timer.intervalPretty());
        } catch (Exception e) {
            log.error(e, "启动 {} 服务失败", getAppName());
            System.exit(1);
        }
    }

    /**
     * 停止应用服务
     */
    public void stop() {
        if (!this.isRunAtomic.get()) {
            log.warn("{} 服务已在停止中", getAppName());
            return;
        }

        log.info("正在停止 {} 服务...", getAppName());
        TimeInterval timer = DateUtil.timer();

        try {
            this.isRunAtomic.set(false);

            // 按与初始化相反的顺序关闭组件
            shutdownComponents();
            log.info("{} 停止成功，总耗时: {}", getAppName(), timer.intervalPretty());
        } catch (Exception e) {
            log.error(e, "停止 {} 服务时发生错误", getAppName());
        } finally {
            deletePidFile();
        }
    }

    /**
     * 初始化所有核心组件
     */
    private void initComponents(String packageName, String[] args) {
        log.debug("正在初始化核心组件...");

        // 1. 加载配置
        PropertiesMgr.load(packageName, args);

        // 2. 初始化数据服务
        DataService.getInstance().init();

        // 3. 初始化脚本管理器
        ScriptManager.getInstance().init();

        // 4. 初始化控制器和事件系统
        ControllerMgr.getInstance().init(packageName);
        EventMgr.getInstance().init(packageName);

        // 5. 初始化网络处理器
        HandlerInterceptorMgr.getInstance().init(packageName);
        HandleHttpClientRequestMgr.getInstance().init(packageName);
        HandleServerToServerRequestMgr.getInstance().init(packageName);
        HandleTcpClientRequestMgr.getInstance().init(packageName);

        // 6. 初始化数据仓库
        RepositoryMgr.getInstance().init(getRepositoryPackages());

        // 7. 初始化网络服务
        NetService.getInstance().init();

        // 8. 执行自定义启动逻辑
        onStart();

        // 9. 启动所有控制器
        ControllerMgr.getInstance().startAll();

        // 10. 创建PID文件
        createPidFile();
    }

    /**
     * 关闭所有核心组件（与初始化顺序相反）
     */
    private void shutdownComponents() {
        // 1. 关闭网络服务
        NetService.getInstance().shutdown();

        // 2. 执行自定义停止逻辑
        onStop();

        // 3. 关闭控制器
        ControllerMgr.getInstance().shutdownAll();

        // 4. 关闭数据仓库
        RepositoryMgr.getInstance().shutdown();

        // 5. 关闭数据服务
        DataService.getInstance().shutdown();

        // 6. 关闭线程池
        CoreThreadPool.getInstance().shutdown();
    }

    /**
     * 创建PID文件（增强版：检查进程是否存活）
     */
    private void createPidFile() {
        String pidFileName = GameConfig.getInstance().getPidFile();
        if (StrUtil.isEmpty(pidFileName)) {
            log.debug("未配置PID文件路径，跳过创建...");
            return;
        }

        try {
            File pidFile = new File(pidFileName);
            // 检查文件是否存在且对应的进程是否存活
            if (FileUtil.exist(pidFile)) {
                String existingPid = FileUtil.readString(pidFile, CharsetUtil.charset("UTF-8")).trim();
                if (isProcessAlive(existingPid)) {
                    throw new RuntimeException("PID文件已存在且进程正在运行: " + existingPid);
                }
                log.warn("PID文件已存在但进程未找到，将覆盖: {}", pidFileName);
            }

            // 创建或覆盖PID文件
            FileUtil.touch(pidFile);
            try (FileWriter writer = new FileWriter(pidFile, false)) {
                writer.write(getCurrentPid());
                writer.flush();
            }
            log.debug("PID文件创建成功: {}", pidFileName);
        } catch (IOException e) {
            throw new RuntimeException("创建PID文件失败: " + pidFileName, e);
        }
    }

    /**
     * 删除PID文件
     */
    private void deletePidFile() {
        String pidFileName = GameConfig.getInstance().getPidFile();
        if (StrUtil.isEmpty(pidFileName)) {
            return;
        }

        File pidFile = new File(pidFileName);
        if (pidFile.exists() && !pidFile.delete()) {
            log.warn("删除PID文件失败，请手动删除: {}", pidFileName);
        }
    }

    /**
     * 获取数据仓库扫描包路径
     */
    private List<String> getRepositoryPackages() {
        Class<? extends BaseGameApplication> appClass = getClass();
        List<String> packages = new ArrayList<>();
        packages.add(appClass.getPackage().getName());

        // 使用Optional简化注解处理
        Optional.ofNullable(appClass.getAnnotation(RepositoryScan.class))
                .map(RepositoryScan::value)
                .ifPresent(scanPackages -> packages.addAll(Arrays.asList(scanPackages)));

        return packages;
    }

    /**
     * 获取当前进程PID
     */
    private String getCurrentPid() {
        String name = runtimeMxBean.getName();
        return name.split("@", 2)[0];
    }

    /**
     * 检查指定PID的进程是否存活
     */
    private boolean isProcessAlive(String pid) {
        if (StrUtil.isEmpty(pid) || !StrUtil.isNumeric(pid)) {
            return false;
        }

        try {
            // 简单的跨平台进程检查（实际使用中可根据OS优化）
            String command = System.getProperty("os.name").toLowerCase().contains("win")
                    ? "tasklist /FI \"PID eq " + pid + "\""
                    : "ps -p " + pid;

            Process process = Runtime.getRuntime().exec(command);
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (Exception e) {
            log.debug("检查进程状态失败，PID: {}", pid, e);
            return false;
        }
    }

    /**
     * 获取应用名称
     */
    protected abstract String getAppName();

    /**
     * 应用启动时的自定义逻辑
     */
    protected abstract void onStart();

    /**
     * 应用停止时的自定义逻辑
     */
    protected abstract void onStop();
}
